/**
 * @file Editor.hpp
 *
 * @date 17/12/2011
 * @author Tales 
 *
 */

#ifndef _CONTROLLER_EDITOR_HPP_
#define _CONTROLLER_EDITOR_HPP_

#include <utility>
#include <bitset>
#include "../common/Color.hpp"
#include "StateIndex.hpp"

namespace yep
{
using namespace std;
//Foward Declarations
class Picture;
class Tool;

/**
 * @brief Gerencia a Picture, encapsulando o acesso desta pela camada View.
 */
class Editor
{
public:
	/**
	 * @brief Construtor default.
	 *
	 * Cria uma Picture 800,600.
	 */
	Editor();

	/**
	 * @brief Cria um editor com uma Picture no tamanho especificado
	 * @param size o tamanho da Picture
	 */
	Editor(pair<int, int> size);

	/**
	 * @brief Destrói tudo
	 */
	~Editor();

	/**
	 * @brief Cria uma Picture no tamanho especificado
	 * @param size o tamanho da Picture
	 */
	void newPicure(pair<int, int> size);

	/**
	 * @brief Carrega uma picture a partir de um arquivo
	 * @param file o endereço do arquivo
	 * @return verdadeiro quando o arquivo foi aberto com sucesso.
	 * @todo substituir por Excepion Handling
	 */
	bool openPicture(string file);

	/**
	 * @brief Salva uma picture para um arquivo
	 * @param file o endereço
	 * @return verdadeiro se conseguiu salvar com sucesso.
	 * @todo substituir por Excepion Handling
	 */
	bool savePicture(string file);

	/**
	 * @brief Blita o conteúdo do Editor no destino.
	 * @param dst o destino
	 */
	void render(SDL_Surface *dst);

	/**
	 * @brief Adiciona uma nova camada, na posição especificada
	 * @param pos a posição que a camada deve ocupar ou -1 para ser a última.
	 */
	void addLayer(int pos = -1);

	/**
	 * @brief Remove o layer especificado
	 * @param layer o número do layer a ser removido ou -1 para remover o layer atualmente selecionado.
	 */
	void removeLayer(int layer = -1);

	/**
	 * @brief Clona o layer atual e posiciona este novo layer na posição indicada.
	 * @param newPos a posição que o novo layer ocupará.
	 */
	void cloneLayer(int newPos = -1);

	/**
	 * @brief Junta as imagens de todas as camadas
	 * @param eraseOthers se verdadeiro, apaga todas as outras camadas
	 */
	void merge(bool eraseOthers);

	/**
	 * @brief Troca as pocições entre o layer atualmente selecionado e o layer indicado
	 * @param other o outro layer
	 */
	void changePosLayer(int other = -1);

	/**
	 * @brief retorna a quantidade de layers existente
	 * @return
	 */
	size_t getLayerCount();

	/**
	 * @brief Chamado quando um botão é pressionado.
	 *
	 * @param pos a Posição onde ocorreu o event. Deve ser relativa apenas à area de desenho.
	 * @param leftButton @b true se o botão esquerdo foi pressionado, @b false se for o direito.
	 *  Outros botões são ignorados, pois são reservados para a interface
	 * @param state O estado dos botões e modificadores, conforme StateIndex.
	 */
	void pressed(pair<int, int> pos, bool leftButton, bitset<5> state);

	/**
	 * @brief Chamado quando um botão é solto.
	 *
	 * @param pos a Posição onde ocorreu o event. Deve ser relativa apenas à area de desenho.
	 * @param leftButton @b true se o botão esquerdo foi solto, @b false se for o direito.
	 *  Outros botões são ignorados, pois são reservados para a interface
	 * @param state O estado dos botões e modificadores, conforme StateIndex.
	 */
	void released(pair<int, int> pos,bool leftButton, bitset<5> state);

	/**
	 * @brief Chamado quando o mouse é movido.
	 * @param pos A posição atual
	 * @param offset O deslocamento que foi feito desde a posição anterior para a atual.
	 * @param state O estado dos botões e modificadores
	 */
	void moved(pair<int, int> pos, pair<int, int> offset, std::bitset<5> state);

	/**
	 * Desfaz última ação.
	 */
	void undo();

	/**
	 * Refaz a última ação.
	 */
	void redo();
	/**
	 * @brief Retorna o número de ferramentas existentes.
	 * @return o número de ferramentas existentes.
	 */
	size_t getToolCount();

	/**
	 * @brief Retorna o nome de determinada ferramenta
	 * @param index o índice da ferramenta
	 * @return uma string com o nome da ferramenta.
	 */
	string getToolName(size_t index);

	/**
	 * Retorna o layer atualmente selecionado
	 * @return um valor x onde 0 <= x <= getLayerCount().
	 */
	int getCurrentLayer() const;

	/**
	 * @brief Retorna a ferramenta selecionada;
	 * @return o índice da ferramenta selecionada;
	 */
	size_t getTool() const;

	/**
	 * @brief Altera o layer selecionado
	 * @param currentLayer um valor x onde 0 <= x <= getLayerCount().
	 */
	void setCurrentLayer(int currentLayer);

	/**
	 * @brief seleciona uma nova ferramenta
	 * @param tool o índice da tool.
	 */
	void setTool(size_t tool);

	/**
	 * @brief Seleciona a area passada a partir da imagem atual.
	 * @param rect a área.
	 */
	void selectFromRect(const SDL_Rect &rect);

	/**
	 * @brief Seleciona a area passada a partir do clipboard.
	 * @return true se houver uma imagem no clipboard;
	 */
	bool selectFromClipboard();

	/**
	 * @brief Copia o selecionado para o clipboard
	 */
	void selectToClipboard();

	/**
	 * @brief Apaga a seleção.
	 */
	void unselect();

	/**
	 * Retorna a superfície selecionada
	 * @return um ponteiro para SDL_Surface, que @b não pode ser destruído.
	 */
    SDL_Surface *getSelected() const
    {
        return selected;
    }

    /**
	 * Retorna a superfície de preview.
	 * @return um ponteiro para SDL_Surface, que @b não pode ser destruído.
	 */
    SDL_Surface *getPreview() const
    {
        return preview;
    }

    /**
	 * @brief obtém a cor selecionada.
	 * @return a cor selecionada
	 */
    Color getColor() const
    {
        return color;
    }

    /**
	 * @brief Altera a cor selecionada
	 * @param color a nova cor.
	 */
    void setColor(Color color)
    {
        this->color = color;
    }

private:
    /**
	 * @brief Não precisávamos disso se meu compilador tivesse implementado chamadas entre construtores.
	 */
    void init(pair<int,int> size);
    SDL_Surface *preview;
    SDL_Surface *selected;
    //zoomLevel
    Color color;
    int currentLayer;
    friend class Tool;
    Picture *picture;
    int tool;
    Tool **tools;
};

} /* namespace yep */
#endif /* _CONTROLLER_EDITOR_HPP_ */
